#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>

#include "pin.H"
#include "pin_trace.h"
#include "pin_taint.h"

using namespace std;
using namespace pintrace;

string gettypename(uint32_t id)
{
	
	switch (id) {
    case REGTYPE_LAST:  return string("REGTYPE_LAST");
    case MEMTYPE_LAST:  return string("MEMTYPE_LAST");
    case VT_NONE:  return string("VT_NONE");
    case VT_REG8:  return string("VT_REG8");
    case VT_REG16:  return string("VT_REG16");
    case VT_REG32:  return string("VT_REG32");
    case VT_REG64:  return string("VT_REG64");
    case VT_REG128:  return string("VT_REG128");
    case VT_MEM8:  return string("VT_MEM8");
    case VT_MEM16:  return string("VT_MEM16");
    case VT_MEM32:  return string("VT_MEM32");
    case VT_MEM64:  return string("VT_MEM64");
    case VT_MEM128:  return string("VT_MEM128");
    case VT_MEM256:  return string("VT_MEM256");
    default: return string("unknow");
	}
}

string getusename(uint32_t id)
{
	
	switch (id) {
    case 0x01:  return string("RD");
    case 0x10:  return string("WR");
    case 0x11:  return string("RW");
    default:  return string("NO");
    }
}

string getlocname(uint32_t id, uint32_t type)
{
    string ret = REG_StringShort(REG(id));
    if(ret[0] == '*')
    {
		//        ret.erase(0, 13);
        stringstream sstrm;
        sstrm << hex << id;
        sstrm.clear();
        ret = sstrm.str();
    }
    return ret;
}

int main(int argc, char **argv) {
	
	pintrace::TraceReader tr(argv[1]);
	
	printf("Frame count: %d\n\n", tr.count());
	printf("============================================================================\n");

      int pos = atoi(argv[2]);
      tr.seek(pos);
      
      int taintpoint = atoi(argv[3]);

      printf("Pos: %d\n", tr.pos());

      pintrace::Frame *af = tr.prev();
      pintrace::StdFrame2 *af2 = (pintrace::StdFrame2 *)af;
      
	ValSpecRec prev;
      prev.type = af2->types[taintpoint];
      prev.loc = af2->locs[taintpoint];
      prev.taint = af2->taint[taintpoint];
      prev.usage = af2->usages[taintpoint];
      prev.value = af2->values[taintpoint];

//      int CMPCount =0;
      
      printf("Standard frame (enhanced).\n");
      printf("Addr: 0x%x\n", af2->addr);
      printf("TID: %d\n", af2->tid);
      printf("Insn length: %d\n", af2->insn_length);
      printf("Values count: %d\n", af2->values_count);

      printf("Insn bytes: ");

      unsigned int len =
         (af2->insn_length == 0) ? MAX_INSN_BYTES : af2->insn_length;

      for (unsigned int i = 0; i < len; i++) {
         printf("%x ", (unsigned char)(af2->rawbytes[i]));
         char temp[10];
         sprintf(temp, "\\x%02hhx", af2->rawbytes[i]);
      }


      printf("\n     Val\t   Taint\t    Locs\t   Types\t  Usages\n");
      printf("\n--------------------------------------------------------------------------\n");
      for (uint32_t i = 0 ; i < af2->values_count ; i ++)
         printf("%8x\t%8x\t%8s\t%8s\t%8s\n", af2->values[i].dword[0], af2->taint[i], getlocname(af2->locs[i], af2->types[i]).c_str(), gettypename(af2->types[i]).c_str(), getusename(af2->usages[i]).c_str());

      printf("============================================================================\n");


//      uint32_t last_addr=0;
	
	while(tr.pos() >= 0) {
      printf("\rPos: %d", tr.pos());
		
	pintrace::Frame *f = tr.prev();
        unsigned int found = 0;

      switch(f->type) {
          case FRM_STD2:
          {
            pintrace::StdFrame2 *sf = (pintrace::StdFrame2 *) f;
            uint32_t i = 0;
            for (i=0; i < sf->values_count ; i ++)
                {
                    if(sf->locs[i] == prev.loc && (sf->usages[i] &0x10) == 0x10)
                        {
                        found = 1;
                      break;
                        }
                }
            if (!found) goto loop;
            for ( i = 0 ; i < sf->values_count ; i ++)
                {
                    if(sf->usages[i] == 0x01 && getlocname(sf->locs[i], sf->types[i])!="eflags" && sf->locs[i]!=prev.loc )//&& getlocname(af2->locs[i], af2->types[i]) != "eflags")
                        {
                        found = 2;
                        break;
                        }
                 }
            if (!found || found == 1) goto loop;

            prev.type = sf->types[i];
            prev.loc = sf->locs[i];
            prev.taint = sf->taint[i];
            prev.usage = sf->usages[i];
            prev.value = sf->values[i];

            unsigned char ins = (unsigned char)(sf->rawbytes[0]);
//            if(ins & 0xfc == 0x3c || (ins & 0xfc == 0x80 && ins != 0x82))
//                CMPCount ++;
            
            printf("\nStandard frame (enhanced).\n");
            printf("Addr: 0x%x\n", sf->addr);
            printf("TID: %d\n", sf->tid);
            printf("Insn length: %d\n", sf->insn_length);
            printf("Values count: %d\n", sf->values_count);

            printf("Insn bytes: ");

            unsigned int len =
               (sf->insn_length == 0) ? MAX_INSN_BYTES : sf->insn_length;

            for (unsigned int i = 0; i < len; i++) {
               printf("%x ", (unsigned char)(sf->rawbytes[i]));
                char temp[10];
                sprintf(temp, "\\x%02hhx", sf->rawbytes[i]);
            }


            printf("\n     Val\t   Taint\t    Locs\t   Types\t  Usages\n");
            printf("\n--------------------------------------------------------------------------\n");
            for (uint32_t i = 0 ; i < sf->values_count ; i ++)
              printf("%8x\t%8x\t%8s\t%8s\t%8s\n", sf->values[i].dword[0], sf->taint[i], getlocname(sf->locs[i], sf->types[i]).c_str(), gettypename(sf->types[i]).c_str(), getusename(sf->usages[i]).c_str());

            printf("============================================================================\n");

            delete f;
            break;
         }

          default:
         break;
      }
	loop:	if(tr.pos()==0)
            break;
       if (prev.taint !=0xffffffff )
        {
        if (prev.taint == 0)
            printf("Not Found!\n");
        else printf("Found!\n");
        return 0;
        }
	}
	//   cerr << acc;
	return 0;
}

